﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Net.Sockets;
using TcpJsonService.Core;

namespace TcpJsonService.Json
{
    /// <summary>
    /// 控制器项
    /// </summary>
    public class ControllerItem
    {
        /// <summary>
        /// 套接字
        /// </summary>
        public Socket Fd { get; set; }

        /// <summary>
        /// 天气代码
        /// </summary>
        public int WeatherCode { get; set; }

        /// <summary>
        /// 一分钟能见度
        /// </summary>
        public int OneMinute { get; set; }

        /// <summary>
        /// 十分钟能见度
        /// </summary>
        public int TenMinutes { get; set; }

        /// <summary>
        /// 硬件状态代码
        /// </summary>
        public int DeviceCode { get; set; }

        /// <summary>
        /// 天气代码对应的值
        /// </summary>
        public string Value
        {
            get
            {
                return WeatherCode switch
                {
                    0x01 => "R-",
                    0x02 => "R",
                    0x03 => "R+",
                    0x04 => "S-",
                    0x05 => "S",
                    0x06 => "S+",
                    0x07 => "P-",
                    0x08 => "P",
                    0x09 => "P+",
                    0x0a => "F-",
                    0x0b => "F",
                    0x0c => "F+",
                    _ => "C",
                };
            }
        }
    }

    /// <summary>
    /// json对接的控制器通道
    /// </summary>
    public class JsonControllerChannel : TcpChannel
    {
        /// <summary>
        /// 线程类
        /// </summary>
        private readonly Task _task;

        /// <summary>
        /// 线程取消功能
        /// </summary>
        private readonly CancellationTokenSource _source = new();

        /// <summary>
        /// 客户端端口-控制器编号
        /// </summary>
        private readonly Dictionary<int, int> _ports = [];

        /// <summary>
        /// 控制器编号-控制器
        /// </summary>
        private readonly Dictionary<int, ControllerItem> _controllers = [];

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="port">本地监听端口</param>
        /// <param name="logger">日志</param>
        /// <param name="configuration">配置项</param>
        public JsonControllerChannel(int port, ILogger logger, IConfiguration configuration)
            : base(port, logger)
        {
            List<int> ports = [];
            configuration.Bind("Json:JsonPorts", ports);
            List<int> ids = [];
            configuration.Bind("Json8:ControllerIds", ids);
            if (ports.Count != ids.Count)
            {
                _logger.LogError("config error");
            }
            else
            {
                for (int i = 0; i < ports.Count; i++)
                {
                    logger.LogInformation($"json port {ports[i]}=>{ids[i]}");
                    _ports.Add(ports[i], ids[i]);
                    _controllers.Add(ids[i], new ControllerItem());
                }
            }

            _task = new Task(GetControllerId, _source.Token);
            _task.Start();
        }

        /// <summary>
        /// 发送灯控制
        /// </summary>
        /// <param name="port">客户端端口</param>
        /// <param name="mode">控制参数</param>
        /// <param name="freq">闪烁频率</param>
        /// <param name="lightness">雾灯亮度</param>
        /// <returns>发送结果</returns>
        public int SendLightControl(int port, int mode, int freq, int lightness)
        {
            if (_ports.TryGetValue(port, out int value))
            {
                int controllerId = value;
                byte[] buffer = new byte[13];
                buffer[0] = 0x81;
                buffer[1] = Convert.ToByte(controllerId);
                buffer[2] = 0x03;
                buffer[3] = Convert.ToByte(mode);
                buffer[4] = lightness switch
                {
                    1 => 0x04,
                    2 => 0x1e,
                    3 => 0x28,
                    4 => 0x32,
                    5 => 0x3c,
                    6 => 0x46,
                    7 => 0x50,
                    _ => 0x5a,
                };
                if (freq == 1)
                {
                    buffer[5] = 0x68;
                    buffer[6] = 0x07;
                    buffer[7] = 0x68;
                    buffer[8] = 0x07;
                }
                else if (freq == 2)
                {
                    buffer[5] = 0x74;
                    buffer[6] = 0x03;
                    buffer[7] = 0x74;
                    buffer[8] = 0x03;
                }
                else if (freq == 3)
                {
                    buffer[5] = 0x7a;
                    buffer[6] = 0x01;
                    buffer[7] = 0x7a;
                    buffer[8] = 0x01;
                }
                else
                {
                    buffer[5] = 0x68;
                    buffer[6] = 0x07;
                    buffer[7] = 0x00;
                    buffer[8] = 0x00;
                }
                buffer[9] = 0x0f;
                buffer[10] = 0x02;
                buffer[11] = 0x04;
                buffer[12] = 0xff;
                Socket socket = _controllers[controllerId].Fd;
                if (socket != null && _accpetSockets.TryGetValue(socket, out _))
                {
                    bool result = Send(_controllers[controllerId].Fd, buffer);
                    _logger.LogInformation($"send {socket.Handle} protocol:{buffer[2]:x2} id:{controllerId:x2} mode:{mode} freq:{freq} light:{lightness} result:{result} buff:{ByteConvert.ToHex(buffer)}");
                    return result ? 0 : -1;
                }
                else
                {
                    return -2;
                }
            }
            else
            {
                return -2;
            }
        }

        /// <summary>
        /// 查询控制器天气
        /// </summary>
        /// <param name="port">客户端端口</param>
        /// <returns>控制器信息</returns>
        public ControllerItem GetWeather(int port)
        {
            if (_ports.TryGetValue(port, out int value))
            {
                return _controllers[value];
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 线程函数
        /// </summary>
        private void GetControllerId()
        {
            byte[] buffer = [0x81, 0x7f, 0x11, 0xff];
            while (!_source.IsCancellationRequested)
            {
                foreach (var s in _accpetSockets)
                {
                    bool found = false;
                    foreach (var c in _controllers)
                    {
                        if (s.Key == c.Value.Fd)
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        Send(s.Key, buffer);
                        Thread.Sleep(1000);
                    }
                }
                Thread.Sleep(1000);
            }
        }

        protected override bool Unpack(Socket socket, List<byte> buffer, ref int offset)
        {
            if (buffer.Count < 4 || buffer[0] != 0x90 || buffer[buffer.Count - 1] != 0xff)
            {
                _logger.LogWarning($"controller protocol format error {buffer.Count} {socket.Handle}");
            }
            else
            {
                int controllerId = buffer[1];
                int protocolId = buffer[2];
                if (_controllers.TryGetValue(controllerId, out ControllerItem item))
                {
                    if (protocolId == 0x11)
                    {
                        item.Fd = socket;
                        _logger.LogInformation($"recv {socket.Handle} protocol:{protocolId:x2} id:{controllerId:x2} buffer:{ByteConvert.ToHex(buffer)}");
                    }
                    else if (protocolId == 0x06)
                    {
                        if (buffer.Count >= 13)
                        {
                            item.WeatherCode = buffer[4];
                            item.OneMinute = buffer[7] * 128 * 128 + buffer[6] * 128 + buffer[5];
                            item.TenMinutes = buffer[10] * 128 * 128 + buffer[9] * 128 + buffer[8];
                            item.DeviceCode = buffer[11];
                            _logger.LogInformation($"recv {socket.Handle} protocol:{protocolId:x2} id:{controllerId:x2} weather:{item.WeatherCode:x2} one:{item.OneMinute} ten:{item.TenMinutes} device:{item.DeviceCode} buffer:{ByteConvert.ToHex(buffer)}");
                        }
                        else
                        {
                            _logger.LogWarning($"protocol not enough size {buffer.Count} {socket.Handle}");
                        }
                    }
                    else if (protocolId == 0x03)
                    {
                        _logger.LogInformation($"recv {socket.Handle} protocol:{protocolId:x2} id:{controllerId:x2} buffer:{ByteConvert.ToHex(buffer)}");
                    }
                }
                else
                {
                    _logger.LogWarning($"unknown controller id {controllerId:x2} {socket.Handle}");
                }
            }
            offset += buffer.Count;
            return true;
        }

        public override void Close()
        {
            _source.Cancel();
            try
            {
                _task.Wait(_source.Token);
            }
            catch (OperationCanceledException)
            {

            }
            base.Close();
        }
    }
}
